package cn.hznc.controller.service.program;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hznc.constant.CommonConstant;
import cn.hznc.constant.SortSubprogramEnum;
import cn.hznc.domain.entity.*;
import cn.hznc.domain.entity.common.EquipmentSubprogramMappingEntity;
import cn.hznc.domain.request.order.SortCondition;
import cn.hznc.domain.request.program.*;
import cn.hznc.domain.response.PageResult;
import cn.hznc.exception.ToolManageEx;
import cn.hznc.exception.ToolManageException;
import cn.hznc.mapper.*;
import cn.hznc.repository.*;
import cn.hznc.utils.CommonUtil;
import cn.hznc.utils.PoiUtil;
import cn.hznc.utils.UUIDUtil;
import cn.hznc.vo.SubProgramUsageReportVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;


/**
 * 主程序服务
 *
 * @Author Administrator
 * @Date 2023/3/14 9:20
 */
@Service
public class ProgramManageService {
    @Resource
    private ProgramMapper programMapper;

    @Resource
    private ProcessCraftMapper processCraftMapper;

    @Resource
    private ProcessCraftProgramMapper processCraftProgramMapper;

    @Resource
    private EquipmentGroupRepository equipmentGroupRepository;

    @Resource
    private SubProgramMapper subProgramMapper;
    @Resource
    private WarehouseRespository warehouseRespository;

    @Resource
    private MachineToolStatusRepository machineToolStatusRepository;

    @Resource
    private EquipmentSubprogramMappingMapper equipmentSubprogramMappingMapper;

    @Resource
    private ProgramDurationTimeRepository programDurationTimeRepository;

    private static final HashMap<String, String> sortEnumMap = new HashMap<>();


    private static final List<String> keyWordList = new ArrayList<>();

    static {
        keyWordList.add("数控车削");
        keyWordList.add("精车车削");
        keyWordList.add("三四轴铣削加工中心");
        keyWordList.add("五轴铣削加工中心");

        sortEnumMap.put("minTime" , "MinTime");
        sortEnumMap.put("maxTime" , "MaxTime");
        sortEnumMap.put("avgTime" , "AvgTime");
        sortEnumMap.put("time" , "Time");
    }

    /**
     * 查询主程序列表（展示多版本）
     * 展示最大版本列表需要写xml
     *
     * @param queryProgramReq queryProgramReq
     * @return
     */
    public PageResult<ProgramEntity> queryProgramList(QueryProgramReq queryProgramReq) {
        PageHelper.startPage(queryProgramReq.getPageNum(), queryProgramReq.getPageSize());
        // 构造模糊查询条件
        LambdaQueryWrapper<ProgramEntity> wrapper = buildQueryWrapper(queryProgramReq);
        PageInfo<ProgramEntity> pageInfo = new PageInfo<>(programMapper.selectList(wrapper));
        return new PageResult<>(pageInfo.getList(),pageInfo.getTotal());
    }

    private LambdaQueryWrapper<ProgramEntity> buildQueryWrapper(QueryProgramReq queryProgramReq) {
        LambdaQueryWrapper<ProgramEntity> wrapper = new LambdaQueryWrapper<>();
        if(StringUtils.isNotEmpty(queryProgramReq.getName())){
            wrapper.like(ProgramEntity::getName, queryProgramReq.getName());
        }
        if (StringUtils.isNotEmpty(queryProgramReq.getProgramNum())){
            wrapper.like(ProgramEntity::getProgramNum, queryProgramReq.getProgramNum());
        }
        if (StringUtils.isNotEmpty(queryProgramReq.getOperator())){
            wrapper.like(ProgramEntity::getOperator, queryProgramReq.getOperator());
        }
        return wrapper;
    }

    /**
     * 编辑请求
     *
     * @param addOrEditProgramReq addOrEditProgramReq
     * @return
     */
    @Transactional
    public boolean addOrEditProgram(AddOrEditProgramReq addOrEditProgramReq) {
        // 处理数据
        ProgramEntity programEntity = new ProgramEntity();
        BeanUtil.copyProperties(addOrEditProgramReq,programEntity);
        if (ObjectUtil.isNotNull(programEntity.getId())){
            programMapper.updateById(programEntity);
        }else {
            String programNum = addOrEditProgramReq.getProgramNum();
            String programCode = "program" + "-" + UUIDUtil.getUUID();
//            //查询对应工序的子工序
//            List<ProcessCraftEntity> connectCraftEntities = processRepository.selectByProcessNum(programNum);
//            //查询对应工艺
//            QueryWrapper<ProcessEntity> processWrapper = new QueryWrapper<>();
//            processWrapper.eq("process_num" , programNum);
//            List<ProcessEntity> processEntities = processMapper.selectList(processWrapper);
//            if(CollectionUtil.isNotEmpty(processEntities)){
//                processEntities.forEach(processEntity -> processEntity.setStatus(1));
//                processMapper.updateBatchById(processEntities);
//            }
//            //查询对应产品
//            QueryWrapper<ProductionEntity> productionWrapper = new QueryWrapper<>();
//            productionWrapper.eq("material_no" , programNum);
//            List<ProductionEntity> productionEntities = productionMapper.selectList(productionWrapper);
//            if(CollectionUtil.isNotEmpty(productionEntities)){
//                productionEntities.forEach(productionEntity -> {
//                    productionEntity.setStatus(CommonConstant.DONE_PRODUCTION);
//                    productionEntity.setProcessStatus(CommonConstant.PROCESS_DONE);
//                });
//                processMapper.updateBatchById(processEntities);
//            }
//            //查询对应工单
//            QueryWrapper<OrderEntity> orderEntityWrapper = new QueryWrapper<>();
//            orderEntityWrapper.eq("material_no" , programNum);
//            List<OrderEntity> orderEntities = orderMapper.selectList(orderEntityWrapper);
//            if(CollectionUtil.isNotEmpty(orderEntities)){
//                orderEntities.forEach(orderEntity -> {
//                    orderEntity.setStatus(CommonConstant.ORDER_PRODUCTION_CONNECT_DONE);
//                });
//                orderMapper.updateBatchById(orderEntities);
//            }
//            //查询对应子工序不为空，通过关键字过滤需要关联程序的子工序
//            if(CollectionUtil.isNotEmpty(connectCraftEntities)) {
//                List<ProcessCraftEntity> updateProcessCraftEntities = new ArrayList<>();
//                connectCraftEntities.forEach(
//                        processCraftEntity -> {
//                            keyWordList.forEach(s -> {
//                                if (processCraftEntity.getName().contains(s)) {
//                                    processCraftEntity.setProgramCode(programCode);
//                                    updateProcessCraftEntities.add(processCraftEntity);
//                                }
//                            });
//                        }
//                );
//                if(CollectionUtil.isNotEmpty(updateProcessCraftEntities)) {
//                    processCraftMapper.updateBatchById(updateProcessCraftEntities);
//                }
//            }
            programEntity.setCode(programCode);
            programEntity.setVersion(CommonConstant.INIT_VERSION);
            programMapper.insert(programEntity);

            //往印射表中加入数据
            List<EquipmentSubprogramMappingEntity> insertEntities = new ArrayList<>();
            List<Integer> equipmentIds = equipmentGroupRepository.selectEquipmentIds();
            if(CollectionUtil.isNotEmpty(equipmentIds)){
                equipmentIds.forEach(equipmentId ->{
                    EquipmentSubprogramMappingEntity equipmentSubprogramMappingEntity = new EquipmentSubprogramMappingEntity();
                    equipmentSubprogramMappingEntity.setProgramCode(programCode);
                    equipmentSubprogramMappingEntity.setEquipmentId(equipmentId);
                    equipmentSubprogramMappingEntity.setEquipmentName(warehouseRespository.getNameByWarehouseId(equipmentId));
                    equipmentSubprogramMappingEntity.setCreateTime(new Date());
                    insertEntities.add(equipmentSubprogramMappingEntity);
                });
            }
            if(CollectionUtil.isNotEmpty(insertEntities)){
                equipmentSubprogramMappingMapper.insertBatchSomeColumn(insertEntities);
            }
        }
        return Boolean.TRUE;
    }

    /**
     * 删除主程序
     *
     * @param deleteProgramReq deleteProgramReq
     * @return
     */
    @Transactional
    public boolean deleteProgram(DeleteProgramReq deleteProgramReq) throws ToolManageException{
        if (CollectionUtil.isEmpty(deleteProgramReq.getIds())){
            throw new ToolManageException(ToolManageEx.PROGRAM_ID_NULL.getCode(), ToolManageEx.TOOL_IDNR_EXIST.getMsg());
        }
        List<ProgramEntity> deletePrograms = programMapper.selectBatchIds(deleteProgramReq.getIds());
        List<String> codes = deletePrograms.stream().map(ProgramEntity::getCode).collect(Collectors.toList());
        //processCraftProgramRepository.deleteBatch(deleteProgramReq.getIds() , new ArrayList<>());
        programMapper.deleteBatchIds(deleteProgramReq.getIds());

        //删除映射表中数据
        QueryWrapper<EquipmentSubprogramMappingEntity> wrapper = new QueryWrapper<>();
        wrapper.in("program_code" , codes);
        List<EquipmentSubprogramMappingEntity> deleteMappings = equipmentSubprogramMappingMapper.selectList(wrapper);
        List<Integer> deleteMappingIds = deleteMappings.stream().map(EquipmentSubprogramMappingEntity::getId).collect(Collectors.toList());
        equipmentSubprogramMappingMapper.deleteBatchIds(deleteMappingIds);

        QueryWrapper<SubProgramEntity> subProgramWrapper = new QueryWrapper<>();
        subProgramWrapper.in("program_code" , codes);
        subProgramMapper.delete(subProgramWrapper);
        return Boolean.TRUE;
    }

    public Object importProgramBoard(MultipartFile file) {
        return PoiUtil.importWordToDocx(file);
    }

    public Boolean connectProgramAndCraft(ConnectProAndCraftReq connectProAndCraftReq) throws ToolManageException {
        ProgramEntity programEntity = programMapper.selectById(connectProAndCraftReq.getProgramId());
        ProcessCraftEntity processCraftEntity = processCraftMapper.selectById(connectProAndCraftReq.getCraftId());
        if(ObjectUtil.isNotNull(programEntity) && ObjectUtil.isNotNull(processCraftEntity)){
            throw new ToolManageException(ToolManageEx.CRAFT_PROGRAM_CONNECT_FAIL.getCode() , ToolManageEx.CRAFT_PROGRAM_CONNECT_FAIL.getMsg());
        }
        ProcessCraftProgramEntity processCraftProgramEntity = new ProcessCraftProgramEntity();
        BeanUtil.copyProperties(connectProAndCraftReq , processCraftProgramEntity);
        processCraftProgramEntity.setIsUsing(1);
        processCraftProgramMapper.insert(processCraftProgramEntity);
        return Boolean.TRUE;
    }

    public Object subProgramUsageReport(SubprogramUsageReportReq subprogramUsageReportReq){
        List<SubProgramUsageReportVo> resultList = new ArrayList<>();
        List<SubProgramUsageReportVo> pageList = new ArrayList<>();
        if(StringUtils.isNotBlank(subprogramUsageReportReq.getProgram())){
            subprogramUsageReportReq.setProgram(subprogramUsageReportReq.getProgram().replaceAll("\\\\" , "\\\\\\\\"));
        }
        resultList = machineToolStatusRepository.subProgramUsageReport(subprogramUsageReportReq);
        SortCondition sortCondition = subprogramUsageReportReq.getSortCondition();
        //对条件查询的orderEntities排序
        if (CollectionUtil.isNotEmpty(resultList) && ObjectUtil.isNotNull(sortCondition)) {
            if (sortEnumMap.containsKey(sortCondition.getSortColumn())) {
                SortSubprogramEnum sortSubprogramEnum = SortSubprogramEnum.valueOf(sortEnumMap.getOrDefault(sortCondition.getSortColumn(), null));
                resultList = sortSubprogramEnum.sortByCondition(resultList, sortCondition.getSortType());
            }
            pageList = CommonUtil.pageList(resultList , subprogramUsageReportReq.getPageNum() , subprogramUsageReportReq.getPageSize());
            //设置机床名
            if(CollectionUtil.isNotEmpty(pageList)){
                pageList.forEach(subProgramUsageReportVo -> subProgramUsageReportVo.setMachineToolName(warehouseRespository.getNameBySnCode(subProgramUsageReportVo.getSnCode())));
            }
        }
        return new PageResult<>(pageList , (long) resultList.size());
//        PageHelper.startPage(subprogramUsageReportReq.getPageNum() , subprogramUsageReportReq.getPageSize());
//        PageInfo<SubProgramUsageReportVo> pageInfo = new PageInfo<>(machineToolStatusRepository.subProgramUsageReport(subprogramUsageReportReq));
//        return new PageResult<>(pageInfo.getList() , pageInfo.getTotal());
    }

    public Object subProgramUsageReportDetail(SubprogramUsageReportReq subprogramUsageReportReq) {
        List<SubProgramUsageReportVo> resultList = new ArrayList<>();
        List<SubProgramUsageReportVo> pageList = new ArrayList<>();
        if(StringUtils.isNotBlank(subprogramUsageReportReq.getProgram())){
            subprogramUsageReportReq.setProgram(subprogramUsageReportReq.getProgram().replaceAll("\\\\" , "\\\\\\\\"));
        }
        resultList = machineToolStatusRepository.subProgramUsageReportDetail(subprogramUsageReportReq);
        SortCondition sortCondition = subprogramUsageReportReq.getSortCondition();
        //对条件查询的orderEntities排序
        if (CollectionUtil.isNotEmpty(resultList) && ObjectUtil.isNotNull(sortCondition)) {
            if (sortEnumMap.containsKey(sortCondition.getSortColumn())) {
                SortSubprogramEnum sortSubprogramEnum = SortSubprogramEnum.valueOf(sortEnumMap.getOrDefault(sortCondition.getSortColumn(), null));
                resultList = sortSubprogramEnum.sortByCondition(resultList, sortCondition.getSortType());
            }
            pageList = CommonUtil.pageList(resultList , subprogramUsageReportReq.getPageNum() , subprogramUsageReportReq.getPageSize());
            //设置机床名
            if(CollectionUtil.isNotEmpty(pageList)){
                pageList.forEach(subProgramUsageReportVo -> subProgramUsageReportVo.setMachineToolName(warehouseRespository.getNameBySnCode(subProgramUsageReportVo.getSnCode())));
            }
        }
        return new PageResult<>(pageList , (long) resultList.size());
    }

    public Object programUsageIndex(ProgramUsageIndex programUsageIndex) {
        PageHelper.startPage(programUsageIndex.getPageNum() , programUsageIndex.getPageSize());
        if(StringUtils.isNotBlank(programUsageIndex.getFromProgram())){
            if(programUsageIndex.getProgram().contains("\\")){
                programUsageIndex.setProgram(programUsageIndex.getProgram().replaceAll("\\\\" , "\\\\\\\\"));
            }else if(programUsageIndex.getProgram().contains("\\/")){
                programUsageIndex.setProgram(programUsageIndex.getProgram().replaceAll("\\/" , "\\//"));
            }
        }
        List<ProgramDurationTimeEntity> resultList = programDurationTimeRepository.programUsageIndex(programUsageIndex);
        PageInfo<ProgramDurationTimeEntity> pageInfo = new PageInfo<>(resultList);
        return new PageResult<>(pageInfo.getList() , pageInfo.getTotal());
    }

    public Object programUsageGroup(ProgramUsageGroupReq programUsageIndex) {
        List<SubProgramUsageReportVo> resultList = programDurationTimeRepository.programUsageGroup(programUsageIndex);
        List<SubProgramUsageReportVo> pageList = new ArrayList<>();
        SortCondition sortCondition = programUsageIndex.getSortCondition();
        //对条件查询的orderEntities排序
        if (CollectionUtil.isNotEmpty(resultList) && ObjectUtil.isNotNull(sortCondition)) {
            if (sortEnumMap.containsKey(sortCondition.getSortColumn())) {
                SortSubprogramEnum sortSubprogramEnum = SortSubprogramEnum.valueOf(sortEnumMap.getOrDefault(sortCondition.getSortColumn(), null));
                resultList = sortSubprogramEnum.sortByCondition(resultList, sortCondition.getSortType());
            }
            pageList = CommonUtil.pageList(resultList , programUsageIndex.getPageNum() , programUsageIndex.getPageSize());
            //设置机床名
            if(CollectionUtil.isNotEmpty(pageList)){
                pageList.forEach(subProgramUsageReportVo -> subProgramUsageReportVo.setMachineToolName(warehouseRespository.getNameBySnCode(subProgramUsageReportVo.getSnCode())));
            }
        }
        pageList = CommonUtil.pageList(resultList , programUsageIndex.getPageNum() , programUsageIndex.getPageSize());
        return new PageResult<>(pageList , (long) resultList.size());
    }

    public void exportProgramTemplate(HttpServletResponse response) {
        String outputFileName = "程序导入模版";
        CommonUtil.exportExcelFile(new Object() , "/template/program/程序导入模版.xlsx" , response , outputFileName);
    }

    @Transactional
    public void importProgramTemplate(List<List<LinkedHashMap>> dataList) {
        List<ProgramEntity> insertProgramList = new ArrayList<>();
        List<SubProgramEntity> insertSubProgramList = new ArrayList<>();
        List<EquipmentSubprogramMappingEntity> addMappingEntities = new ArrayList<>();
        if(CollectionUtil.isNotEmpty(dataList)){
            for (List<LinkedHashMap> mapList : dataList) {
                LinkedHashMap linkedHashMap = mapList.get(0);

                String programNum = linkedHashMap.get("1").toString();
                String programName = linkedHashMap.get("3").toString();
                String programDescription = linkedHashMap.get("5").toString();
                String operator = linkedHashMap.get("7").toString();
                String programCode = "program" + "-" + UUIDUtil.getUUID();
                //校验数据
                if(ObjectUtil.isNull(programNum) || ObjectUtil.isNull(programName)){
                    return;
                }
                List<ProgramEntity> programEntities = programMapper.selectList(new QueryWrapper<>());
                List<String> existProgramNums = programEntities
                        .stream()
                        .map(ProgramEntity::getProgramNum)
                        .collect(Collectors.toList());
                if(existProgramNums.contains(programNum)){
                    return;
                }
                ProgramEntity programEntity = new ProgramEntity();
                programEntity.setProgramNum(programNum);
                programEntity.setName(programName);
                programEntity.setDescription(programDescription);
                programEntity.setOperator(operator);
                programEntity.setCode(programCode);
                insertProgramList.add(programEntity);
                //保存子程序信息 以及主程序map信息
                if(mapList.size()>2){
                    //根据关联机床构建子程序
                    List<Integer> equipmentIds = equipmentGroupRepository.selectEquipmentIds();
                    //往印射表中添加关联关系
                    if (CollectionUtil.isNotEmpty(equipmentIds)) {
                        for (int i = 0; i < equipmentIds.size(); i++) {
                            Integer equipmentId = equipmentIds.get(i);
                            EquipmentSubprogramMappingEntity equipmentSubprogramMappingEntity = new EquipmentSubprogramMappingEntity();
                            equipmentSubprogramMappingEntity.setEquipmentId(equipmentId);
                            equipmentSubprogramMappingEntity.setProgramCode(programCode);
                            equipmentSubprogramMappingEntity.setCreateTime(new Date());
                            equipmentSubprogramMappingEntity.setEquipmentName(warehouseRespository.getNameByWarehouseId(equipmentId));
                            addMappingEntities.add(equipmentSubprogramMappingEntity);
                        }
                    }
                    //持久化子程序
                    for (int i = 2; i < mapList.size(); i++) {
                        LinkedHashMap linkedHashMap1 = mapList.get(i);
                        SubProgramEntity subProgramEntity = new SubProgramEntity();
                        subProgramEntity.setName(linkedHashMap1.get("2").toString());
                        subProgramEntity.setCode("subProgram" + "-" + UUIDUtil.getUUID());
                        subProgramEntity.setProgramCode(programCode);
                        subProgramEntity.setVersion(CommonConstant.INIT_VERSION);
                        try {
                            subProgramEntity.setRpm(Integer.valueOf(linkedHashMap1.get("6").toString()));
                        } catch (Exception e) {

                        }
                        try {
                            subProgramEntity.setFeed(new BigDecimal(linkedHashMap1.get("7").toString()));
                        } catch (Exception e) {

                        }
                        try {
                            subProgramEntity.setExtension(new BigDecimal(linkedHashMap1.get("5").toString()));
                        } catch (Exception e) {

                        }
                        try {
                            subProgramEntity.setSeq(Integer.valueOf(linkedHashMap1.get("0").toString()));
                        } catch (Exception e) {

                        }
                        try {
                            subProgramEntity.setToolCode(linkedHashMap1.get("1").toString());
                        } catch (Exception e) {

                        }
                        try {
                            subProgramEntity.setToolModel(linkedHashMap1.get("3").toString());
                        } catch (Exception e) {

                        }
                        try {
                            subProgramEntity.setShankModel(linkedHashMap1.get("4").toString());
                        } catch (Exception e) {

                        }
                        insertSubProgramList.add(subProgramEntity);
                    }
                }
            }
        }
        if(CollectionUtil.isNotEmpty(insertProgramList)){
            insertProgramList = insertProgramList.stream().filter(distinctByKey(ProgramEntity::getProgramNum)).collect(Collectors.toList());
            programMapper.insertBatchSomeColumn(insertProgramList);
        }
        if(CollectionUtil.isNotEmpty(insertSubProgramList)){
            subProgramMapper.insertBatchSomeColumn(insertSubProgramList);
        }
        if(CollectionUtil.isNotEmpty(addMappingEntities)){
            equipmentSubprogramMappingMapper.insertBatchSomeColumn(addMappingEntities);
        }
    }

    static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }
}
